package com.bupt.hotel.hvac.controller;

import com.bupt.hotel.hvac.model.domain.ServiceObject;
import com.bupt.hotel.hvac.model.domain.WaitingObject;
import com.bupt.hotel.hvac.model.dto.ServiceRequestDTO;
import com.bupt.hotel.hvac.model.entity.RoomState;
import com.bupt.hotel.hvac.model.enums.ACMode;
import com.bupt.hotel.hvac.model.enums.FanSpeed;
import com.bupt.hotel.hvac.service.ACService;
import com.bupt.hotel.hvac.service.CentralControllerService;
import com.bupt.hotel.hvac.service.SchedulerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 空调服务控制器 - 统一接口标准
 * 提供空调状态查询、控制等功能
 */
@Slf4j
@RestController
@RequestMapping("/api/ac")
public class ACController {

    private final CentralControllerService centralControllerService;
    private final ACService acService;
    private final SchedulerService schedulerService;

    public ACController(CentralControllerService centralControllerService,
                        ACService acService,
                        SchedulerService schedulerService) {
        this.centralControllerService = centralControllerService;
        this.acService = acService;
        this.schedulerService = schedulerService;
    }

    /**
     * 获取所有空调状态
     * GET /api/ac/all
     */
    @GetMapping("/all")
    public List<Map<String, Object>> getAllACs() {
        List<ServiceObject> serviceQueue = schedulerService.getServiceQueue();
        
        return serviceQueue.stream()
                .map(this::convertServiceObjectToACInfo)
                .collect(Collectors.toList());
    }

    /**
     * 获取单个空调状态
     * GET /api/ac/{acId}
     */
    @GetMapping("/{acId}")
    public Map<String, Object> getAC(@PathVariable Integer acId) {
        List<ServiceObject> serviceQueue = schedulerService.getServiceQueue();
        
        if (acId < 1 || acId > serviceQueue.size()) {
            // 返回空调未被使用的状态
            Map<String, Object> result = new HashMap<>();
            result.put("acId", acId);
            result.put("servingRoomId", null);
            result.put("on", false);
            result.put("mode", null);
            result.put("fanSpeed", null);
            result.put("targetTemp", 0);
            result.put("currentTemp", 0);
            result.put("requestTime", null);
            result.put("serviceStartTime", null);
            result.put("serviceEndTime", null);
            result.put("serviceDuration", 0);
            result.put("cost", 0);
            result.put("priority", 0);
            result.put("serviceTime", 0);
            return result;
        }
        
        ServiceObject serviceObject = serviceQueue.get(acId - 1);
        return convertServiceObjectToACInfo(serviceObject);
    }

    /**
     * 获取指定房间的空调请求状态
     * GET /api/ac/room/{roomId}
     */
    @GetMapping("/room/{roomId}")
    public Map<String, Object> getRoomACStatus(@PathVariable String roomId) {
        RoomState room = acService.getRoomState(roomId);
        
        if (room == null) {
            Map<String, Object> result = new HashMap<>();
            result.put("error", "房间不存在");
            return result;
        }
        
        Map<String, Object> result = new HashMap<>();
        result.put("roomId", room.getRoomId());
        result.put("on", room.getIsOn());
        result.put("mode", room.getMode() != null ? room.getMode().name() : null);
        result.put("fanSpeed", room.getFanSpeed() != null ? room.getFanSpeed().name() : null);
        result.put("targetTemp", room.getTargetTemp());
        result.put("currentTemp", room.getCurrentTemp());
        result.put("status", room.getStatus() != null ? room.getStatus().name() : null);
        result.put("totalCost", room.getTotalCost());
        result.put("serviceStartTime", room.getServiceStartTime() != null 
                ? room.getServiceStartTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 
                : null);
        
        return result;
    }

    /**
     * 房间打开空调
     * POST /api/ac/room/{roomId}/start
     */
    @PostMapping("/room/{roomId}/start")
    public Map<String, Object> startAC(@PathVariable String roomId) {
        log.info("房间 {} 请求开启空调", roomId);
        
        try {
            centralControllerService.turnOn(roomId);
            
            Map<String, Object> result = new HashMap<>();
            result.put("data", "空调请求已提交");
            return result;
        } catch (Exception e) {
            log.error("房间 {} 开启空调失败: {}", roomId, e.getMessage());
            Map<String, Object> result = new HashMap<>();
            result.put("error", e.getMessage());
            return result;
        }
    }

    /**
     * 更新空调参数
     * PUT /api/ac/room/{roomId}/adjust
     */
    @PutMapping("/room/{roomId}/adjust")
    public Map<String, Object> adjustAC(@PathVariable String roomId,
                                         @RequestParam(required = false) String mode,
                                         @RequestParam(required = false) String fanSpeed,
                                         @RequestParam(required = false) BigDecimal targetTemp) {
        log.info("房间 {} 调整空调参数 - 模式: {}, 风速: {}, 目标温度: {}", roomId, mode, fanSpeed, targetTemp);
        
        try {
            RoomState room = acService.getRoomState(roomId);
            if (room == null || !room.getIsOn()) {
                Map<String, Object> result = new HashMap<>();
                result.put("error", "房间未开机");
                return result;
            }
            
            // 更新模式
            if (mode != null) {
                ACMode acMode = ACMode.valueOf(mode);
                acService.setMode(roomId, acMode);
            }
            
            // 构建请求DTO
            ServiceRequestDTO dto = new ServiceRequestDTO();
            dto.setTargetTemp(targetTemp != null ? targetTemp : room.getTargetTemp());
            dto.setFanSpeed(fanSpeed != null ? FanSpeed.valueOf(fanSpeed) : room.getFanSpeed());
            
            Map<String, Object> result = centralControllerService.sendRequest(roomId, dto);
            return result;
        } catch (Exception e) {
            log.error("房间 {} 调整空调参数失败: {}", roomId, e.getMessage());
            Map<String, Object> result = new HashMap<>();
            result.put("error", e.getMessage());
            return result;
        }
    }

    /**
     * 更改温度
     * PUT /api/ac/room/{roomId}/temp
     */
    @PutMapping("/room/{roomId}/temp")
    public Map<String, Object> changeTemp(@PathVariable String roomId,
                                           @RequestParam BigDecimal targetTemp) {
        log.info("房间 {} 调整温度: {}°C", roomId, targetTemp);
        
        try {
            RoomState room = acService.getRoomState(roomId);
            if (room == null || !room.getIsOn()) {
                Map<String, Object> result = new HashMap<>();
                result.put("error", "房间未开机");
                return result;
            }
            
            ServiceRequestDTO dto = new ServiceRequestDTO();
            dto.setTargetTemp(targetTemp);
            dto.setFanSpeed(room.getFanSpeed());
            
            Map<String, Object> result = centralControllerService.sendRequest(roomId, dto);
            return result;
        } catch (Exception e) {
            log.error("房间 {} 调整温度失败: {}", roomId, e.getMessage());
            Map<String, Object> result = new HashMap<>();
            result.put("error", e.getMessage());
            return result;
        }
    }

    /**
     * 房间请求关空调
     * POST /api/ac/room/{roomId}/cancel
     */
    @PostMapping("/room/{roomId}/cancel")
    public Map<String, Object> cancelAC(@PathVariable String roomId) {
        log.info("房间 {} 请求关闭空调", roomId);
        
        try {
            centralControllerService.turnOff(roomId);
            
            Map<String, Object> result = new HashMap<>();
            result.put("message", "空调已关闭");
            return result;
        } catch (Exception e) {
            log.error("房间 {} 关闭空调失败: {}", roomId, e.getMessage());
            Map<String, Object> result = new HashMap<>();
            result.put("error", e.getMessage());
            return result;
        }
    }

    /**
     * 获取当前等待队列
     * GET /api/ac/queue/waiting
     */
    @GetMapping("/queue/waiting")
    public List<Map<String, Object>> getWaitingQueue() {
        List<WaitingObject> waitingQueue = schedulerService.getWaitingQueue();
        
        return waitingQueue.stream()
                .map(this::convertWaitingObjectToMap)
                .collect(Collectors.toList());
    }

    /**
     * 获取当前服务队列
     * GET /api/ac/queue/service
     */
    @GetMapping("/queue/service")
    public List<Map<String, Object>> getServiceQueue() {
        List<ServiceObject> serviceQueue = schedulerService.getServiceQueue();
        
        return serviceQueue.stream()
                .map(this::convertServiceObjectToMap)
                .collect(Collectors.toList());
    }

    /**
     * 更改模式
     * PUT /api/ac/room/{roomId}/mode
     */
    @PutMapping("/room/{roomId}/mode")
    public Map<String, Object> changeMode(@PathVariable String roomId,
                                           @RequestParam String mode) {
        log.info("房间 {} 切换模式: {}", roomId, mode);
        
        try {
            ACMode acMode = ACMode.valueOf(mode);
            acService.setMode(roomId, acMode);
            
            Map<String, Object> result = new HashMap<>();
            result.put("message", "模式已切换");
            return result;
        } catch (Exception e) {
            log.error("房间 {} 切换模式失败: {}", roomId, e.getMessage());
            Map<String, Object> result = new HashMap<>();
            result.put("error", e.getMessage());
            return result;
        }
    }

    /**
     * 更改风速
     * PUT /api/ac/room/{roomId}/fanspeed
     */
    @PutMapping("/room/{roomId}/fanspeed")
    public Map<String, Object> changeFanSpeed(@PathVariable String roomId,
                                               @RequestParam String fanSpeed) {
        log.info("房间 {} 调整风速: {}", roomId, fanSpeed);
        
        try {
            RoomState room = acService.getRoomState(roomId);
            if (room == null || !room.getIsOn()) {
                Map<String, Object> result = new HashMap<>();
                result.put("error", "房间未开机");
                return result;
            }
            
            FanSpeed speed = FanSpeed.valueOf(fanSpeed);
            
            ServiceRequestDTO dto = new ServiceRequestDTO();
            dto.setTargetTemp(room.getTargetTemp());
            dto.setFanSpeed(speed);
            
            Map<String, Object> result = centralControllerService.sendRequest(roomId, dto);
            return result;
        } catch (Exception e) {
            log.error("房间 {} 调整风速失败: {}", roomId, e.getMessage());
            Map<String, Object> result = new HashMap<>();
            result.put("error", e.getMessage());
            return result;
        }
    }

    /**
     * 转换ServiceObject到空调信息
     */
    private Map<String, Object> convertServiceObjectToACInfo(ServiceObject obj) {
        Map<String, Object> result = new HashMap<>();
        
        RoomState room = acService.getRoomState(obj.getRoomId());
        
        result.put("acId", obj.getId());
        result.put("servingRoomId", obj.getRoomId());
        result.put("on", true);
        result.put("mode", room != null && room.getMode() != null ? room.getMode().name() : null);
        result.put("fanSpeed", obj.getFanSpeed() != null ? obj.getFanSpeed().name() : null);
        result.put("targetTemp", obj.getTargetTemp());
        result.put("currentTemp", obj.getCurrentTemp());
        result.put("requestTime", obj.getServiceStartTime() != null 
                ? LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(obj.getServiceStartTime()), 
                        ZoneId.systemDefault()).toString() 
                : null);
        result.put("serviceStartTime", obj.getServiceStartTime() != null 
                ? LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(obj.getServiceStartTime()), 
                        ZoneId.systemDefault()).toString() 
                : null);
        result.put("serviceEndTime", null);
        result.put("serviceDuration", obj.getServiceDuration());
        result.put("cost", obj.getCost());
        result.put("priority", getPriority(obj.getFanSpeed()));
        result.put("serviceTime", obj.getServiceDuration());
        
        return result;
    }

    /**
     * 转换ServiceObject到Map
     */
    private Map<String, Object> convertServiceObjectToMap(ServiceObject obj) {
        Map<String, Object> result = new HashMap<>();
        result.put("roomId", obj.getRoomId());
        result.put("fanSpeed", obj.getFanSpeed() != null ? obj.getFanSpeed().name() : null);
        result.put("targetTemp", obj.getTargetTemp());
        result.put("currentTemp", obj.getCurrentTemp());
        result.put("serviceStartTime", obj.getServiceStartTime());
        result.put("serviceDuration", obj.getServiceDuration());
        result.put("powerConsumption", obj.getPowerConsumption());
        result.put("cost", obj.getCost());
        return result;
    }

    /**
     * 转换WaitingObject到Map
     */
    private Map<String, Object> convertWaitingObjectToMap(WaitingObject obj) {
        Map<String, Object> result = new HashMap<>();
        result.put("roomId", obj.getRoomId());
        result.put("fanSpeed", obj.getFanSpeed() != null ? obj.getFanSpeed().name() : null);
        result.put("targetTemp", obj.getTargetTemp());
        result.put("currentTemp", obj.getCurrentTemp());
        result.put("requestTime", obj.getWaitStartTime());
        result.put("waitingDuration", obj.getWaitDuration());
        return result;
    }

    /**
     * 根据风速获取优先级
     */
    private int getPriority(FanSpeed fanSpeed) {
        if (fanSpeed == null) return 0;
        switch (fanSpeed) {
            case HIGH:
                return 3;
            case MEDIUM:
                return 2;
            case LOW:
                return 1;
            default:
                return 0;
        }
    }
}
